"""
:synopsis: Add Topology
:authors: Riley Baird (OK), Emma Baker (OK)

"""
from os.path import join
from pathlib import Path

import arcpy

from ...lib.gdbsession import NG911Session
from ...lib.misc import unwrap_to_dict, unwrap
from ...lib.session import config
from ...lib.topology import topology_config

_rds = config.gdb_info.required_dataset_name  # "[r]equired [d]ata[s]et"
_rdst = topology_config.required_dataset_topology_name  # "[r]equired [d]ata[s]et [t]opology"
_ods = config.gdb_info.optional_dataset_name  # "[o]ptional [d]ata[s]et"
_odst = topology_config.optional_dataset_topology_name  # "[o]ptional [d]ata[s]et [t]opology"

# ParamDict = dict[str, arcpy.Parameter]
# ParamValueDict = dict[str, GPParameterValue | list[GPParameterValue]]
# ToolValidationMethod = Callable[[Any, list[arcpy.Parameter]], None]
# ToolValidationDictMethod = Callable[[Any, list[arcpy.Parameter]], None]
# ToolExecuteMethod = Callable[[Any, list[arcpy.Parameter], GPMessenger], None]
# ToolExecuteDictsMethod = Callable[[Any, ParamDict, ParamValueDict, GPMessenger], None]
#
# @overload
# def params_as_dict(func: ToolValidationDictMethod) -> ToolValidationMethod: ...
#
# @overload
# def params_as_dict(func: ToolExecuteDictsMethod) -> ToolExecuteMethod: ...
#
# def params_as_dict(func: ToolValidationDictMethod | ToolExecuteDictsMethod) -> ToolValidationMethod | ToolExecuteMethod:
#     arg_count = len(signature(func).parameters.keys())
#     wraps_decorator = wraps(func, tuple(set(WRAPPER_ASSIGNMENTS) - {"__annotations__"}))
#     if arg_count == 2:
#         @wraps_decorator
#         def _inner(self, parameters: list[arcpy.Parameter]):
#             return func(self, params_to_dict(parameters))
#     elif arg_count == 3:
#         @wraps_decorator
#         def _inner(self, parameters: list[arcpy.Parameter], messages: GPMessenger):
#             return func(self, params_to_dict(parameters), messages)
#     else:
#         raise ValueError("Expected function with parameters (self, parameters) or (self, parameters, messages).")
#     return _inner


class AddNG911Topology:
    """
    Class describing an ArcGIS Python Toolbox tool: "Add Topology".
    """
    
    def __init__(self):
        """Define the tool (tool name is the name of the class)."""
        self.label = "Add Topology"
        self.description = ""
        self.category = "3 - Enhancement"
        self.canRunInBackground = False

    def getParameterInfo(self):
        """Define parameter definitions"""
        params = [
            arcpy.Parameter(
                displayName="NG911 Geodatabase",
                name="gdb",
                datatype="DEWorkspace",
                parameterType="Required",
                direction="Input"
            ),
            arcpy.Parameter(
                displayName="Validate",
                name="validate",
                datatype="GPBoolean",
                parameterType="Optional",
                direction="Input",
                enabled=False
            ),
            # OUTPUT
            arcpy.Parameter(
                displayName="Output Required Topology",
                name="output_required_topology",
                datatype="DETopology",
                parameterType="Derived",
                direction="Output"
            ),
            arcpy.Parameter(
                displayName="Output Optional Topology",
                name="output_optional_topology",
                datatype="DETopology",
                parameterType="Derived",
                direction="Output"
            )
        ]
        return params

    def isLicensed(self):
        """Set whether tool is licensed to execute."""
        return True

    # @params_as_dict
    # def updateParameters(self, parameters: dict[str, arcpy.Parameter]):
    def updateParameters(self, parameters: list[arcpy.Parameter]):
        """Modify the values and properties of parameters before internal
        validation is performed.  This method is called whenever a parameter
        has been changed."""
        gdb_p, validate_p = parameters[:2]
        gdb: str
        validate: bool
        gdb, validate = unwrap(parameters[:2])
        try:
            rdst_path_str: str = join(gdb, _rds, _rdst)
            odst_path_str: str = join(gdb, _ods, _odst)
            if gdb_p.altered and arcpy.Exists(gdb):  # (arcpy.Exists(rdst_path_str) or arcpy.Exists(odst_path_str)):
                validate_p.enabled = True
                if not validate_p.altered:
                    validate_p.value = True
            else:
                raise
        except:
            validate_p.enabled = False
            validate_p.value = None

    def updateMessages(self, parameters: list[arcpy.Parameter]):
        """Modify the messages created by internal validation for each tool
        parameter.  This method is called after internal validation."""
        gdb: str
        validate: bool
        gdb, validate = unwrap(parameters[:2])
        already_exists_messages: list[str] = []
        if gdb and Path(gdb).exists():
            if arcpy.Exists(join(gdb, _rds, _rdst)):
                already_exists_messages.append(f"Topology '{_rds}/{_rdst}' already exists and will be deleted.")
            if arcpy.Exists(join(gdb, _ods, _odst)):
                already_exists_messages.append(f"Topology '{_ods}/{_odst}' already exists and will be deleted.")
        if already_exists_messages:
            parameters[0].setWarningMessage(" ".join(already_exists_messages))
        else:
            parameters[0].clearMessage()

    def execute(self, parameters, messages):
        """The source code of the tool."""
        gdb: str
        validate: bool
        gdb, validate = unwrap(parameters[:2])
        with NG911Session(gdb, False, messenger=messages) as session:
            modified_rdst, modified_odst = session.add_and_configure_topologies(True)
            if validate:
                session.validate_topologies()
            parameters[-2].value = session.str_path_to(_rdst) if modified_rdst else None
            parameters[-1].value = session.str_path_to(_odst) if modified_odst else None


if __name__ == "__main__":
    raise Exception("This module is a dependency of an ArcGIS Python Toolbox and should not be executed directly.")